﻿namespace Microsoft.SharePoint.Client
{
    using System;
    using System.Collections.Generic;
    using System.Globalization;
    using System.IO;
    using System.Reflection;
    using System.Text;
    using System.Xml;

    internal sealed class ChunkStringBuilder
    {
        private StringBuilder m_sb;
        private List<StringBuilder> m_sbs;
        private const int MaxChunkLength = 0x4e20;
        private const int StringBuilderMaxCapacity = 0x4e84;

        public ChunkStringBuilder()
        {
            this.m_sbs = new List<StringBuilder>();
            this.m_sb = CreateStringBuilder();
            this.m_sbs.Add(this.m_sb);
        }

        public ChunkStringBuilder(string value)
        {
            this.m_sbs = new List<StringBuilder>();
            if (value != null)
            {
                if (value.Length <= 0x4e20)
                {
                    this.m_sb = CreateStringBuilder();
                    this.m_sb.Append(value);
                    this.m_sbs.Add(this.m_sb);
                }
                else
                {
                    for (int i = 0; i < value.Length; i += 0x4e20)
                    {
                        int count = 0x4e20;
                        if ((i + count) > value.Length)
                        {
                            count = value.Length - i;
                        }
                        this.m_sb = CreateStringBuilder();
                        this.m_sb.Append(value, i, count);
                        this.m_sbs.Add(this.m_sb);
                    }
                }
            }
        }

        public ChunkStringBuilder Append(bool value)
        {
            this.m_sb.Append(value);
            this.CreateNewBufferIfNecessary();
            return this;
        }

        public ChunkStringBuilder Append(byte value)
        {
            this.m_sb.Append(value);
            this.CreateNewBufferIfNecessary();
            return this;
        }

        public ChunkStringBuilder Append(char value)
        {
            this.m_sb.Append(value);
            this.CreateNewBufferIfNecessary();
            return this;
        }

        public ChunkStringBuilder Append(decimal value)
        {
            this.m_sb.Append(value);
            this.CreateNewBufferIfNecessary();
            return this;
        }

        public ChunkStringBuilder Append(double value)
        {
            this.m_sb.Append(value);
            this.CreateNewBufferIfNecessary();
            return this;
        }

        public ChunkStringBuilder Append(short value)
        {
            this.m_sb.Append(value);
            this.CreateNewBufferIfNecessary();
            return this;
        }

        public ChunkStringBuilder Append(int value)
        {
            this.m_sb.Append(value);
            this.CreateNewBufferIfNecessary();
            return this;
        }

        public ChunkStringBuilder Append(char[] value)
        {
            return this.Append(value, 0, value.Length);
        }

        public ChunkStringBuilder Append(long value)
        {
            this.m_sb.Append(value);
            this.CreateNewBufferIfNecessary();
            return this;
        }

        public ChunkStringBuilder Append(sbyte value)
        {
            this.m_sb.Append(value);
            this.CreateNewBufferIfNecessary();
            return this;
        }

        public ChunkStringBuilder Append(float value)
        {
            this.m_sb.Append(value);
            this.CreateNewBufferIfNecessary();
            return this;
        }

        public ChunkStringBuilder Append(string value)
        {
            if (value != null)
            {
                int startIndex = 0;
                this.CreateNewBufferIfNecessary();
                while (startIndex < value.Length)
                {
                    int num2 = 0x4e20 - this.m_sb.Length;
                    int length = Math.Min(value.Length - startIndex, num2);
                    this.m_sb.Append(value.Substring(startIndex, length));
                    startIndex += length;
                    this.CreateNewBufferIfNecessary();
                }
            }
            return this;
        }

        public ChunkStringBuilder Append(ushort value)
        {
            this.m_sb.Append(value);
            this.CreateNewBufferIfNecessary();
            return this;
        }

        public ChunkStringBuilder Append(uint value)
        {
            this.m_sb.Append(value);
            this.CreateNewBufferIfNecessary();
            return this;
        }

        public ChunkStringBuilder Append(ulong value)
        {
            this.m_sb.Append(value);
            this.CreateNewBufferIfNecessary();
            return this;
        }

        public ChunkStringBuilder Append(char value, int repeatCount)
        {
            this.CreateNewBufferIfNecessary();
            while (repeatCount > 0)
            {
                int num = 0x4e20 - this.m_sb.Length;
                int num2 = (repeatCount > num) ? num : repeatCount;
                this.m_sb.Append(value, num2);
                repeatCount -= num2;
                this.CreateNewBufferIfNecessary();
            }
            return this;
        }

        public ChunkStringBuilder Append(char[] value, int startIndex, int count)
        {
            if (value != null)
            {
                this.CreateNewBufferIfNecessary();
                while (count > 0)
                {
                    int num = 0x4e20 - this.m_sb.Length;
                    int charCount = (count > num) ? num : count;
                    this.m_sb.Append(value, startIndex, charCount);
                    startIndex += charCount;
                    count -= charCount;
                    this.CreateNewBufferIfNecessary();
                }
            }
            return this;
        }

        public ChunkStringBuilder Append(string value, int startIndex, int count)
        {
            if (value != null)
            {
                this.CreateNewBufferIfNecessary();
                while (count > 0)
                {
                    int num = 0x4e20 - this.m_sb.Length;
                    int num2 = (count > num) ? num : count;
                    this.m_sb.Append(value, startIndex, num2);
                    startIndex += num2;
                    count -= num2;
                    this.CreateNewBufferIfNecessary();
                }
            }
            return this;
        }

        public ChunkStringBuilder AppendLine()
        {
            this.Append(Environment.NewLine);
            return this;
        }

        public ChunkStringBuilder AppendLine(string value)
        {
            this.Append(value);
            this.AppendLine();
            return this;
        }

        private void CreateNewBufferIfNecessary()
        {
            if (this.m_sb.Length >= 0x4e20)
            {
                this.m_sb = CreateStringBuilder();
                this.m_sbs.Add(this.m_sb);
            }
        }

        private static StringBuilder CreateStringBuilder()
        {
            return new StringBuilder(0x10, 0x4e84);
        }

        public TextWriter CreateTextWriter(IFormatProvider formatProvider)
        {
            return new ChunkStringWriter(this, formatProvider);
        }

        public XmlWriter CreateXmlWriter()
        {
            XmlWriterSettings settings = new XmlWriterSettings {
                OmitXmlDeclaration = true,
                NewLineHandling = NewLineHandling.Entitize
            };
            return XmlWriter.Create(this.CreateTextWriter(CultureInfo.InvariantCulture), settings);
        }

        private void SurrogatePairAdjust()
        {
            for (int i = this.m_sbs.Count - 1; i >= 0; i--)
            {
                if (this.m_sbs[i].Length == 0)
                {
                    this.m_sbs.RemoveAt(i);
                }
            }
            for (int j = 0; j < (this.m_sbs.Count - 1); j++)
            {
                char highSurrogate = this.m_sbs[j][this.m_sbs[j].Length - 1];
                char lowSurrogate = this.m_sbs[j + 1][0];
                if (char.IsSurrogatePair(highSurrogate, lowSurrogate))
                {
                    this.m_sbs[j].Append(lowSurrogate);
                    this.m_sbs[j + 1].Remove(0, 1);
                }
            }
        }

        public void WriteContentAsRawXml(XmlWriter writer)
        {
            this.SurrogatePairAdjust();
            for (int i = 0; i < this.m_sbs.Count; i++)
            {
                writer.WriteRaw(this.m_sbs[i].ToString());
            }
        }

        public void WriteContentAsUTF8(Stream stream)
        {
            this.SurrogatePairAdjust();
            for (int i = 0; i < this.m_sbs.Count; i++)
            {
                StringBuilder builder = this.m_sbs[i];
                byte[] bytes = Encoding.UTF8.GetBytes(builder.ToString());
                stream.Write(bytes, 0, bytes.Length);
            }
        }

        public void WriteContentTo(TextWriter writer)
        {
            for (int i = 0; i < this.m_sbs.Count; i++)
            {
                writer.Write(this.m_sbs[i].ToString());
            }
        }

        public char this[int index]
        {
            get
            {
                for (int i = 0; i < this.m_sbs.Count; i++)
                {
                    StringBuilder builder = this.m_sbs[i];
                    if (index >= builder.Length)
                    {
                        index -= builder.Length;
                    }
                    else
                    {
                        return builder[index];
                    }
                }
                throw new ArgumentOutOfRangeException("index");
            }
            set
            {
                for (int i = 0; i < this.m_sbs.Count; i++)
                {
                    StringBuilder builder = this.m_sbs[i];
                    if (index >= builder.Length)
                    {
                        index -= builder.Length;
                    }
                    else
                    {
                        builder[index] = value;
                        return;
                    }
                }
                throw new ArgumentOutOfRangeException("index");
            }
        }

        public int Length
        {
            get
            {
                int num = 0;
                for (int i = 0; i < this.m_sbs.Count; i++)
                {
                    num += this.m_sbs[i].Length;
                }
                return num;
            }
            set
            {
                if (value < 0)
                {
                    throw new ArgumentOutOfRangeException("value");
                }
                int num = 0;
                num = 0;
                while (num < this.m_sbs.Count)
                {
                    StringBuilder builder = this.m_sbs[num];
                    if (value >= builder.Length)
                    {
                        value -= builder.Length;
                    }
                    else
                    {
                        builder.Length = value;
                        value = 0;
                        this.m_sb = builder;
                        break;
                    }
                    num++;
                }
                if (value == 0)
                {
                    if ((num + 1) < this.m_sbs.Count)
                    {
                        this.m_sbs.RemoveRange(num + 1, (this.m_sbs.Count - num) - 1);
                    }
                }
                else
                {
                    this.Append('\0', value);
                }
            }
        }
    }
}

